﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BTalk.Network;
using BTalk.Crypto.Algorithms;
using System.IO;
using System.Numerics;
using BTalk.Crypto;

namespace BTalk
{
    public partial class MainWindow : Form
    {
        private INetworkManager NetworkManager { get; set; }

        public MainWindow()
        {
            InitializeComponent();
        }

        private void MainWindow_Load(object sender, EventArgs e)
        {
            NetworkManager = new NetworkManager();
            NetworkManager.MessageReceived += manager_MessageReceived;
            NetworkManager.FileReceived += NetworkManager_FileReceived;
            NetworkManager.AlgorithmNegotiated += NetworkManager_AlgorithmNegotiated;
        }

        void NetworkManager_AlgorithmNegotiated(byte[] configurationData, string algorithmName)
        {
            if (algorithmName == "Aes")
            {
                AesDialog dialog = new AesDialog();
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    var cipher = new Aes(dialog.GetMode(), Encoding.UTF8.GetBytes(dialog.GetPassword()));
                    cipher.Configuration = configurationData;
                    NetworkManager.SetCipher(cipher, false);
                }
            }
            if (algorithmName == "Rsa")
            {
                RsaDialog dialog = new RsaDialog();

                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    var encryptionKey = new RsaKey()
                        {
                            N = BigInteger.Parse(dialog.Ne),
                            E = BigInteger.Parse(dialog.E)
                        };
                    var decryptionKey = new RsaKey()
                    {
                        N = BigInteger.Parse(dialog.Nd),
                        D = BigInteger.Parse(dialog.D)
                    };

                    RsaMode mode;
                    bool modeValid = Enum.TryParse(dialog.Mode, true, out mode);
                    if (!modeValid)
                    {
                        MessageBox.Show("Invalid mode name provided");
                        return;
                    }

                    var rsa = new Rsa(RsaMode.Normal)
                    {
                        Configuration = new Tuple<RsaKey, RsaKey>(encryptionKey, decryptionKey)
                    };

                    NetworkManager.SetCipher(rsa, false);
                    var key = NetworkManager.GetCipher().Decode(configurationData);

                    ICryptoStrategy underneathAlgorithm = null;

                    if (mode == RsaMode.Hybrid)
                    {
                        underneathAlgorithm = new Aes(System.Security.Cryptography.CipherMode.ECB, key);
                    }

                    (NetworkManager.GetCipher() as Rsa).Mode = RsaMode.Hybrid;
                    (NetworkManager.GetCipher() as Rsa).SymmetricAlgorithm = underneathAlgorithm;   
                }
            }
        }

        void NetworkManager_FileReceived(byte[] fileData, string fileName)
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(() => SaveFileAs(fileName, fileData)));
                return;
            }

            SaveFileAs(fileName, fileData);
        }

        private void SaveFileAs(string fileName, byte[] fileData)
        {
            var dialog = new SaveFileDialog();
            dialog.FileName = fileName;
            var result = dialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                File.WriteAllBytes(dialog.FileName, fileData);
            }
        }

        private void manager_MessageReceived(string message)
        {
            if (outputMessageBox.InvokeRequired)
            {
                outputMessageBox.Invoke(new MethodInvoker(() => InvokeOutputBox(message)));
                return;
            }

            InvokeOutputBox(message);
        }

        private void InvokeOutputBox(string message)
        {
            outputMessageBox.Text += Environment.NewLine + message;
        }

        private void connectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ConnectDialog dialog = new ConnectDialog();
            var result = dialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                NetworkManager.Connect(dialog.GetIPAddress(), dialog.GetPortNumber());
            }
        }

        private void SendBtn_Click(object sender, EventArgs e)
        {
            NetworkManager.SendMessage(inputMessageBox.Text);
            inputMessageBox.Clear();
        }

        private void caesarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NetworkManager.SetCipher(new Caesar(), false);
        }

        private void sendFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var openFileDialog = new OpenFileDialog();
            var result = openFileDialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                var fileData = File.ReadAllBytes(openFileDialog.FileName);

                NetworkManager.SendFile(openFileDialog.SafeFileName, fileData);
            }
        }

        private void vigenereToolStripMenuItem_Click(object sender, EventArgs e)
        {
            KeyDialog dialog = new KeyDialog();
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                NetworkManager.SetCipher(new Vigenere(UTF8Encoding.UTF8.GetBytes(dialog.GetKey())), false);
            }
        }

        private void noneToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NetworkManager.SetCipher(null, false);
        }

        private void aesRijandelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AesDialog dialog = new AesDialog();

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                NetworkManager.SetCipher(new Aes(dialog.GetMode(), Encoding.UTF8.GetBytes(dialog.GetPassword())), false);
            }
            
        }

        private void rSAToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RsaDialog dialog = new RsaDialog();

            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                var encryptionKey =  new RsaKey()
                    {
                        N = BigInteger.Parse(dialog.Ne),
                        E = BigInteger.Parse(dialog.E)
                    };
                var decryptionKey = new RsaKey()
                {
                    N = BigInteger.Parse(dialog.Nd),
                    D = BigInteger.Parse(dialog.D)
                };

                RsaMode mode;
                bool modeValid = Enum.TryParse(dialog.Mode, true, out mode);
                if (!modeValid)
                {
                    MessageBox.Show("Invalid mode name provided");
                    return;
                }
                ICryptoStrategy underneathAlgorithm = null;

                if (mode == RsaMode.Hybrid)
                {
                    underneathAlgorithm = new Aes(System.Security.Cryptography.CipherMode.ECB, null);
                }

                var rsa = new Rsa(mode, underneathAlgorithm)
                {
                    Configuration = new Tuple<RsaKey, RsaKey>(encryptionKey, decryptionKey)
                };

                if (mode == RsaMode.Hybrid)
                {
                    NetworkManager.SetCipher(rsa, true);
                }
                else
                {
                    NetworkManager.SetCipher(rsa, false);
                }
            }
        }
    }
}
